package com.bingoogolapple.qrcode.core;

import ohos.agp.components.AttrSet;
import ohos.agp.components.Component;
import ohos.agp.components.surfaceprovider.SurfaceProvider;
import ohos.agp.graphics.Surface;
import ohos.agp.graphics.SurfaceOps;
import ohos.agp.utils.Rect;
import ohos.app.Context;
import ohos.eventhandler.EventHandler;
import ohos.eventhandler.EventRunner;
import ohos.media.camera.CameraKit;
import ohos.media.camera.device.Camera;
import ohos.media.camera.device.CameraConfig;
import ohos.media.camera.device.CameraStateCallback;
import ohos.media.camera.device.FrameConfig;
import ohos.media.camera.params.Metadata;
import ohos.media.image.Image;
import ohos.media.image.ImageReceiver;
import ohos.media.image.common.ImageFormat;
import ohos.multimodalinput.event.MmiPoint;
import ohos.multimodalinput.event.TouchEvent;

import java.nio.ByteBuffer;

import static ohos.media.camera.device.Camera.FrameConfigType.FRAME_CONFIG_PICTURE;
import static ohos.media.camera.device.Camera.FrameConfigType.FRAME_CONFIG_PREVIEW;
import static ohos.media.camera.params.Metadata.FlashMode.*;

public class CameraPreview extends SurfaceProvider implements Component.TouchEventListener, SurfaceOps.Callback {


    private static final int IMAGE_RCV_CAPACITY = 2;
    private Camera mCamera;
    private Surface previewSurface;
    private boolean mPreviewing = true;
    private boolean mSurfaceCreated = false;
    private FrameConfig.Builder framePreviewConfigBuilder;
    private FrameConfig.Builder framePictureConfigBuilder;
    private CameraConfig.Builder cameraConfigBuilder;
    private ImageReceiver imageReceiver;
    private float mOldDist = 1f;
    private EventHandler eventHandler;
    private QRCodeView mQrCodeView;
    private CameraPreview mCameraPreview;
    private EventHandler mAutoFocusHandler;

    public void setImageReceiver(ImageReceiver imageReceiver) {
        this.imageReceiver = imageReceiver;
    }


    public void setPreviewCallback(PreviewCallback cb) {
        mPreviewCallback = cb;
    }

    public interface PreviewCallback {
        void onPreviewFrame(Image image);
    }

    ;

    private PreviewCallback mPreviewCallback;

    public CameraPreview(Context context, QRCodeView qrCodeView) {
        this(context, null, qrCodeView);
        LogUtil.info("CameraPreview...");

    }

    public CameraPreview(Context context, AttrSet attrSet, QRCodeView qrCodeView) {
        this(context, attrSet, null, qrCodeView);
    }

    public CameraPreview(Context context, AttrSet attrSet, String styleName, QRCodeView qrCodeView) {
        super(context, attrSet, styleName);
        setTouchEventListener(this);
        initView(qrCodeView);
    }

    public void initView(QRCodeView qrCodeView) {
        this.mQrCodeView = qrCodeView;
        LogUtil.error("调用initView，开始创建相机实例");
        setVisibility(Component.VISIBLE);
        setFocusable(Component.FOCUS_ENABLE);
        setTouchFocusable(true);
        mAutoFocusHandler = new EventHandler(EventRunner.getMainEventRunner());
        pinToZTop(false);
        if (getSurfaceOps().isPresent()) {
            getSurfaceOps().get().addCallback(CameraPreview.this);
        }
        eventHandler = new EventHandler(EventRunner.create("cameraPreview"));
    }






    void stopCameraPreview() {
        LogUtil.error("stopCameraPreview...");
        try {
            mPreviewing = false;
            removeSurfaceCallback();

            if (mCamera != null) {
                mCamera.stopLoopingCapture();
                mCamera.release();
                mCamera = null;
            }
            previewSurface = null;
            framePreviewConfigBuilder = null;
            framePictureConfigBuilder = null;

        } catch (Exception exception) {
            LogUtil.error("释放相机失败");
        }


    }

    private void removeSurfaceCallback() {
        LogUtil.error("removeSurfaceCallback...");
        if (getSurfaceOps() != null) {
            getSurfaceOps().get().removeCallback(this);
        }
    }

    void openFlashlight() {
        framePreviewConfigBuilder.setFlashMode(FLASH_ALWAYS_OPEN);
        try {
            mCamera.triggerLoopingCapture(framePreviewConfigBuilder.build());
        } catch (Exception exception) {
            LogUtil.error("openFlashlight");
        }

    }

    void closeFlashlight() {
        framePreviewConfigBuilder.setFlashMode(FLASH_CLOSE);
        try {
            mCamera.triggerLoopingCapture(framePreviewConfigBuilder.build());
        } catch (Exception exception) {
            LogUtil.error("closeFlashlight");
        }
    }

    private boolean flashLightAvailable() {
        return false;
    }

    void onScanBoxRectChanged(Rect scanRect) {
        if (mCamera == null || scanRect == null || scanRect.left <= 0 || scanRect.top <= 0) {
            return;
        }
        int centerX = scanRect.getCenterX();
        int centerY = scanRect.getCenterY();
        int rectHalfWidth = scanRect.getWidth() / 2;
        int rectHalfHeight = scanRect.getHeight() / 2;

        BGAQRCodeUtil.printRect("转换前", scanRect);

        if (BGAQRCodeUtil.isPortrait(getContext())) {
            int temp = centerX;
            centerX = centerY;
            centerY = temp;

            temp = rectHalfWidth;
            rectHalfWidth = rectHalfHeight;
            rectHalfHeight = temp;
        }
        scanRect = new Rect(centerX - rectHalfWidth, centerY - rectHalfHeight, centerX + rectHalfWidth, centerY + rectHalfHeight);
        BGAQRCodeUtil.printRect("转换后", scanRect);

        BGAQRCodeUtil.d("扫码框发生变化触发对焦测光");
        handleFocusMetering(scanRect.getCenterX(), scanRect.getCenterY(), scanRect.getWidth(), scanRect.getHeight());
    }

    boolean isPreviewing() {
        return mCamera != null && mPreviewing && mSurfaceCreated;
    }


    class CameraStateCallbackImpl extends CameraStateCallback {

        @Override
        public void onCreated(Camera camera) {
            super.onCreated(camera);
            LogUtil.error("CameraStateCallbackImpl--onCreated....");
            LogUtil.info("CameraStateCallbackImpl onCreated...");
            mCamera = camera;
            cameraConfigBuilder = camera.getCameraConfigBuilder();
            if (cameraConfigBuilder == null) {
                return;
            }
            CameraConfig cameraConfig = cameraConfigBuilder
                    .addSurface(previewSurface)
                    .addSurface(imageReceiver.getRecevingSurface())
                    .build();
            camera.configure(cameraConfig);

        }

        @Override
        public void onConfigured(Camera camera) {
            LogUtil.info("onConfigured....");
            LogUtil.error("CameraStateCallbackImpl--onConfigured....");
            if (mCamera == null) {
                return;
            }
            if (previewSurface == null) {
                return;
            }

            if (framePreviewConfigBuilder == null) {
                framePreviewConfigBuilder = camera.getFrameConfigBuilder(FRAME_CONFIG_PREVIEW);
            }
            framePreviewConfigBuilder.addSurface(previewSurface);
            framePreviewConfigBuilder.addSurface(imageReceiver.getRecevingSurface());

            try {
                camera.triggerLoopingCapture(framePreviewConfigBuilder.build());
            } catch (Exception e) {
                LogUtil.error("onConfigured....error....");


            }

        }
    }

    @Override
    public void surfaceCreated(SurfaceOps surfaceOps) {
        LogUtil.error("surfaceCreated...");
        surfaceOps.setFixedSize(2340, 1080);
        previewSurface = surfaceOps.getSurface();
        mSurfaceCreated = true;

        mContext.getUITaskDispatcher().asyncDispatch(new Runnable() {
            @Override
            public void run() {
                cameraInit();
            }
        });
    }

    private void cameraInit() {
        LogUtil.error("调用cameraInit，开始创建相机实例");
        CameraKit mCamerakit = CameraKit.getInstance(mContext.getApplicationContext());
        if (mCamerakit == null || mCamerakit.getCameraIds().length <= 0) {
            return;
        }
        String cameraId = mCamerakit.getCameraIds()[0];
        imageReceiver = ImageReceiver.create(2340, 1080, ImageFormat.JPEG, 3);
        imageReceiver.setImageArrivalListener(imageArrivalListener);
        CameraStateCallbackImpl cameraStateCallback = new CameraStateCallbackImpl();
        mCamerakit.createCamera(cameraId, cameraStateCallback, eventHandler);
    }

    private byte[] translateImageToJpeg(Image image) {
        Image.Component component = image.getComponent(ImageFormat.ComponentType.JPEG);
        byte[] data = new byte[component.remaining()];
        ByteBuffer buffer = component.getBuffer();
        buffer.get(data);
        return data;
    }


    private final ImageReceiver.IImageArrivalListener imageArrivalListener = new ImageReceiver.IImageArrivalListener() {
        @Override
        public void onImageArrival(ImageReceiver imageReceiver) {

                Image image = imageReceiver.readLatestImage();
                if (image == null) {
                    return;
                }

                LogUtil.error("image返回成功....");

                if (mPreviewCallback != null) {
                    mPreviewCallback.onPreviewFrame(image);
                }

        }
    };

    @Override
    public void surfaceChanged(SurfaceOps surfaceOps, int format, int width, int height) {
        LogUtil.info("surfaceChanged... format:" + format + ",w:" + width + ",h:" + height);
        LogUtil.error("surfaceChanged....");

    }

    @Override
    public void surfaceDestroyed(SurfaceOps surfaceOps) {
        LogUtil.error("surfaceDestroyed...");
        mSurfaceCreated = false;
        stopCameraPreview();
    }


    @Override
    public boolean onTouchEvent(Component component, TouchEvent event) {
        if (!isPreviewing()) {
            return false;
        }

        int pointCount = event.getPointerCount();

        if (pointCount == 1) {
            // 预览帧变焦值变更
            MmiPoint point = event.getPointerScreenPosition(0);
            Rect rec = new Rect((int) point.getX(), (int) point.getY(), 20, 20);
        }

        if (event.getPointerCount() == 2) {
            switch (event.getAction()) {
                case TouchEvent.OTHER_POINT_DOWN:
                    mOldDist = BGAQRCodeUtil.calculateFingerSpacing(event);
                    LogUtil.error("mOldDist:" + mOldDist);
                    break;
                case TouchEvent.POINT_MOVE:
                    float newDist = BGAQRCodeUtil.calculateFingerSpacing(event);
                    if (newDist > mOldDist) {
                        handleZoom(true, mCamera);
                    } else if (newDist < mOldDist) {
                        handleZoom(false, mCamera);
                    }
                    break;
            }
        }

        return false;
    }

    private void handleZoom(boolean isZoomIn, Camera camera) {
        float zoom = framePreviewConfigBuilder.getZoomValue();
        LogUtil.error("zoom: " + zoom + ",isZoomIn：" + isZoomIn);
        if (isZoomIn && zoom < 10) {
            BGAQRCodeUtil.d("放大");
            zoom++;
        } else if (!isZoomIn && zoom > 0) {
            BGAQRCodeUtil.d("缩小");
            zoom--;
        } else {
            BGAQRCodeUtil.d("既不放大也不缩小");
        }
        framePreviewConfigBuilder.setZoom(zoom);
        mCamera.triggerLoopingCapture(framePreviewConfigBuilder.build());
    }

    private void handleFocusMetering(float originFocusCenterX, float originFocusCenterY,
                                     int originFocusWidth, int originFocusHeight) {

    }

    /**
     * 连续对焦
     */
    private void startContinuousAutoFocus() {
        mAutoFocusHandler.postTimingTask(doAutoFocus, 1000);

    }
    private Runnable doAutoFocus = new Runnable() {
        public void run() {
            if ( mSurfaceCreated) {
                safeAutoFocus(true);
            }
        }
    };

    public void safeAutoFocus(boolean state) {
        LogUtil.error( "safeAutoFocus, state = " + state);
        try {
            if (mCamera != null) {
                FrameConfig.Builder builder = mCamera.getFrameConfigBuilder(FRAME_CONFIG_PREVIEW);
                if (state) {
                    builder.setAfTrigger(Metadata.AfTrigger.AF_TRIGGER_START);
                    builder.setAfMode(Metadata.AfMode.AF_MODE_CONTINUOUS, null);
                } else {
                    builder.setAfTrigger(Metadata.AfTrigger.AF_TRIGGER_CANCEL);
                    builder.setAfMode(Metadata.AfMode.AF_MODE_OFF, null);
                }
                mCamera.triggerLoopingCapture(builder.build());
            }
        } catch (RuntimeException re) {
            startContinuousAutoFocus(); // wait 1 sec and then do check again
        }
    }

    interface Delegate {
        void onStartPreview(ImageReceiver imageReceiver);
    }

}
